﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Inventory.cs" company="">
//   
// </copyright>
// <summary>
//   Inventory is a static object enabling, to request all orders that have been traded in the past (inventory), traded now
//   and request also all opens orders that remains in the database.
// </summar y>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;

namespace Systemathics.FrameWork
{
    public class Inventories : IDisposable
    {
        private readonly SystemathicsEntities db;
        private readonly Instrument instrument;

        public Dictionary<Guid, Order> InventoryOrders { get; private set; }
        public Dictionary<Guid, Order> TradedOrders { get; private set; }
        public Dictionary<Guid, Order> OpenOrders { get; private set; }

        public Inventories(Instrument instrument)
        {
            db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString());
            OpenOrders = new Dictionary<Guid, Order>();
            this.instrument = instrument;
        }
        public void Inventory(DateTime date, Guid strategyId)
        {
            InventoryOrders = new Dictionary<Guid, Order>();
            var query = db.DBStrategies.Where(u => u.ID == strategyId);
            if (query.Any())
            {
                query.FirstOrDefault().DBOrder.Load();
                var upToYesterdayOrders = query.FirstOrDefault().DBOrder.Where(g => (Guid)g.DBInstrumentsReference.EntityKey.EntityKeyValues[0].Value == instrument.Id && g.CreationDate < date);
                foreach (var order in upToYesterdayOrders)
                {
                    var isOpen = false;
                    order.DBExecutions.Load();
                    order.DBOrderStatus.Load();
                    foreach (var s in order.DBOrderStatus)
                    {
                        if (s.Status == "ACK_CANCEL")
                            instrument.StaticData.Fees.Cancellation(order.RequestedQuantity, new decimal(order.RequestedPrice));
                        else if (s.Status == "ACK_MODIFY")
                            instrument.StaticData.Fees.Modification(order.RequestedQuantity, new decimal(order.RequestedPrice));
                        else if (order.TimeInForce == "GTC" && (s.Status != "REJECT" && s.Status != "ACK_CANCEL" && s.Status != "FILLED"))
                            isOpen = true;
  
                    }
                    foreach (var execution in order.DBExecutions)
                    {
                        instrument[Expo.Inventory].Add((OrderSide)Enum.Parse(typeof(OrderSide), order.Side), execution.ExecutedQuantity, new decimal(execution.ExecutedPrice));
                        instrument.StaticData.Fees.ExecutionInventory(execution.ExecutedQuantity, new decimal(execution.ExecutedPrice));
                    }
                    var ostyle = (OrderStyle)Enum.Parse(typeof(OrderStyle), order.Style);
                    var oside = (OrderSide)Enum.Parse(typeof(OrderSide), order.Side);
                    var o = new Order(order.ID, instrument.StaticData, ostyle, oside, (decimal)order.RequestedPrice, order.RequestedQuantity, strategyId);
                    var ot = new OrderTracker(o);
                    ot.SetTotalExecutedQuantity(instrument[Expo.Traded].Balance);
                    ot.SetExecutedAveragePrice(instrument[Expo.Traded].BalancePrice);
                    InventoryOrders[o.Id] = ot;
                    if (isOpen)
                        OpenOrders[o.Id] = ot;
                }
            }
        }
        public void Traded(DateTime date, Guid strategyId)
        {
            TradedOrders = new Dictionary<Guid, Order>();
            var query = db.DBStrategies.Where(u => u.ID == strategyId);
            if (query.Any())
            {
                query.FirstOrDefault().DBOrder.Load();
                var todayOrders = query.FirstOrDefault().DBOrder.Where(g => (Guid)g.DBInstrumentsReference.EntityKey.EntityKeyValues[0].Value == instrument.Id && g.CreationDate >= date);
                foreach (var order in todayOrders)
                {
                    var isOpen = false;
                    order.DBExecutions.Load();
                    order.DBOrderStatus.Load();
                    foreach (var s in order.DBOrderStatus)
                    {
                        if (s.Status == "ACK_CANCEL")
                            instrument.StaticData.Fees.Cancellation(order.RequestedQuantity, new decimal(order.RequestedPrice));
                        else if (s.Status == "ACK_MODIFY")
                            instrument.StaticData.Fees.Modification(order.RequestedQuantity, new decimal(order.RequestedPrice));
                        else if ((order.TimeInForce == "Day" || order.TimeInForce == "GTC") && (s.Status != "REJECT" && s.Status != "ACK_CANCEL" && s.Status != "FILLED"))
                            isOpen = true;
                    }

                  
                    var exp = new InstrumentExposition(instrument);

                    foreach (var execution in order.DBExecutions)
                    {
                        instrument.StaticData.Fees.Execution(execution.ExecutedQuantity, new decimal(execution.ExecutedPrice));
                        instrument[Expo.Traded].Add((OrderSide)Enum.Parse(typeof(OrderSide), order.Side), execution.ExecutedQuantity, new decimal(execution.ExecutedPrice));
                        exp.Add((OrderSide)Enum.Parse(typeof(OrderSide), order.Side), execution.ExecutedQuantity, new decimal(execution.ExecutedPrice));
                    }
                    var ostyle = (OrderStyle)Enum.Parse(typeof(OrderStyle), order.Style);
                    var oside = (OrderSide)Enum.Parse(typeof(OrderSide), order.Side);
                    var o = new Order(order.ID, instrument.StaticData, ostyle, oside, (decimal)order.RequestedPrice, order.RequestedQuantity, strategyId);
                    var ot = new OrderTracker(o);
                    ot.SetTotalExecutedQuantity(exp.Balance);
                    ot.SetExecutedAveragePrice(exp.BalancePrice);
                    TradedOrders[o.Id] = ot;
                    if(isOpen)
                        OpenOrders[o.Id] = ot;
                }
            }
        }
        public void Opens(Guid strategyId)
        {
            var orders = db.DBOrder.Where(delegate(DBOrder order)
            {
                order.DBStrategiesReference.Load();
                if (order.DBStrategies.ID == strategyId && (order.TimeInForce == "Day" || order.TimeInForce == "GTC"))
                {
                    order.DBOrderStatus.Load();
                    var result = order.DBOrderStatus.OrderByDescending(u => u.StatusTime).LastOrDefault();
                    if (result.Status != "REJECT" || result.Status != "ACK_CANCEL" || result.Status != "FILLED")
                        return true;
                }
                return false;
            });

            foreach (var order in orders)
            {
                var ostyle = (OrderStyle)Enum.Parse(typeof(OrderStyle), order.Style);
                var oside = (OrderSide)Enum.Parse(typeof(OrderSide), order.Side);
                var o = new Order(order.ID, instrument.StaticData, ostyle, oside, (decimal)order.RequestedPrice, order.RequestedQuantity, strategyId);
                OpenOrders[o.Id] = o;
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            db.Dispose();
        }

        #endregion
    }
}